//! 页面管理器单元测试
//!
//! 测试页面管理器的磁盘持久化功能，确保P0优先级任务的正确实现

use super::page::{PageManager, PageType, PAGE_SIZE};
use crate::{Result, Error};
use std::sync::Arc;
use tempfile::TempDir;

#[cfg(test)]
mod tests {
    use super::*;

    /// 测试页面管理器基础功能
    #[test]
    fn test_page_manager_basic() -> Result<()> {
        let page_manager = PageManager::new(10);
        
        // 测试分配页面
        let page_id1 = page_manager.allocate_page(PageType::Data)?;
        let page_id2 = page_manager.allocate_page(PageType::Index)?;
        let page_id3 = page_manager.allocate_page(PageType::Metadata)?;
        
        assert_eq!(page_id1, 1);
        assert_eq!(page_id2, 2);
        assert_eq!(page_id3, 3);
        
        // 测试读取页面
        let page1 = page_manager.read_page(page_id1)?;
        let page2 = page_manager.read_page(page_id2)?;
        let page3 = page_manager.read_page(page_id3)?;
        
        assert_eq!(page1.header.page_id, page_id1);
        assert_eq!(page1.header.page_type, PageType::Data);
        assert_eq!(page2.header.page_id, page_id2);
        assert_eq!(page2.header.page_type, PageType::Index);
        assert_eq!(page3.header.page_id, page_id3);
        assert_eq!(page3.header.page_type, PageType::Metadata);
        
        Ok(())
    }

    /// 测试磁盘存储功能
    #[test]
    fn test_disk_storage() -> Result<()> {
        let temp_dir = TempDir::new()
            .map_err(|e| Error::storage(format!("创建临时目录失败: {}", e)))?;
        let data_file = temp_dir.path().join("test.db");
        
        // 创建页面管理器并分配页面
        let page_manager = PageManager::with_disk_storage(10, &data_file)?;
        
        let page_id1 = page_manager.allocate_page(PageType::Data)?;
        let page_id2 = page_manager.allocate_page(PageType::Index)?;
        
        // 读取页面并修改数据
        let mut page1 = page_manager.read_page(page_id1)?;
        let mut page2 = page_manager.read_page(page_id2)?;
        
        // 修改页面数据
        page1.data[0] = 0xAA;
        page1.data[1] = 0xBB;
        page2.data[0] = 0xCC;
        page2.data[1] = 0xDD;
        
        // 写入页面
        page_manager.write_page(Arc::new(page1))?;
        page_manager.write_page(Arc::new(page2))?;
        
        // 刷新到磁盘
        page_manager.flush_dirty_pages()?;
        
        // 验证文件存在且有内容
        assert!(data_file.exists());
        let file_size = std::fs::metadata(&data_file)
            .map_err(|e| Error::storage(format!("获取文件大小失败: {}", e)))?
            .len();
        assert!(file_size > 0);
        
        Ok(())
    }

    /// 测试数据恢复功能
    #[test]
    fn test_data_recovery() -> Result<()> {
        let temp_dir = TempDir::new()
            .map_err(|e| Error::storage(format!("创建临时目录失败: {}", e)))?;
        let data_file = temp_dir.path().join("test.db");
        
        // 第一阶段：创建并写入数据
        {
            let page_manager = PageManager::with_disk_storage(10, &data_file)?;
            
            let page_id1 = page_manager.allocate_page(PageType::Data)?;
            let page_id2 = page_manager.allocate_page(PageType::Index)?;
            
            let mut page1 = page_manager.read_page(page_id1)?;
            let mut page2 = page_manager.read_page(page_id2)?;
            
            // 写入特定数据
            page1.data[0] = 0x11;
            page1.data[1] = 0x22;
            page2.data[0] = 0x33;
            page2.data[1] = 0x44;
            
            page_manager.write_page(Arc::new(page1))?;
            page_manager.write_page(Arc::new(page2))?;
            page_manager.flush_dirty_pages()?;
        }
        
        // 第二阶段：重新创建页面管理器并验证数据恢复
        {
            let page_manager = PageManager::with_disk_storage(10, &data_file)?;
            
            let page1 = page_manager.read_page(1)?;
            let page2 = page_manager.read_page(2)?;
            
            // 验证页面类型
            assert_eq!(page1.header.page_type, PageType::Data);
            assert_eq!(page2.header.page_type, PageType::Index);
            
            // 验证数据内容
            assert_eq!(page1.data[0], 0x11);
            assert_eq!(page1.data[1], 0x22);
            assert_eq!(page2.data[0], 0x33);
            assert_eq!(page2.data[1], 0x44);
        }
        
        Ok(())
    }

    /// 测试页面缓存功能
    #[test]
    fn test_page_cache() -> Result<()> {
        let page_manager = PageManager::new(3); // 小缓存用于测试LRU
        
        // 分配多个页面
        let page_id1 = page_manager.allocate_page(PageType::Data)?;
        let page_id2 = page_manager.allocate_page(PageType::Data)?;
        let page_id3 = page_manager.allocate_page(PageType::Data)?;
        let page_id4 = page_manager.allocate_page(PageType::Data)?;
        
        // 读取页面（应该触发缓存）
        let _page1 = page_manager.read_page(page_id1)?;
        let _page2 = page_manager.read_page(page_id2)?;
        let _page3 = page_manager.read_page(page_id3)?;
        let _page4 = page_manager.read_page(page_id4)?; // 应该导致page1被驱逐
        
        // 再次读取page1（应该从磁盘重新加载）
        let _page1_again = page_manager.read_page(page_id1)?;
        
        Ok(())
    }

    /// 测试页面统计信息
    #[test]
    fn test_page_statistics() -> Result<()> {
        let page_manager = PageManager::new(10);
        
        // 分配一些页面
        let _page_id1 = page_manager.allocate_page(PageType::Data)?;
        let _page_id2 = page_manager.allocate_page(PageType::Index)?;
        let _page_id3 = page_manager.allocate_page(PageType::Metadata)?;
        
        // 读取页面
        let _page1 = page_manager.read_page(1)?;
        let _page2 = page_manager.read_page(2)?;
        let _page3 = page_manager.read_page(3)?;
        
        // 获取统计信息
        let stats = page_manager.get_statistics();
        
        assert!(stats.total_pages >= 3);
        assert!(stats.cache_hits >= 0);
        assert!(stats.cache_misses >= 3); // 至少3次缓存未命中
        
        Ok(())
    }

    /// 测试页面序列化和反序列化
    #[test]
    fn test_page_serialization() -> Result<()> {
        let temp_dir = TempDir::new()
            .map_err(|e| Error::storage(format!("创建临时目录失败: {}", e)))?;
        let data_file = temp_dir.path().join("test.db");
        
        let page_manager = PageManager::with_disk_storage(10, &data_file)?;
        
        // 创建页面并设置特定数据
        let page_id = page_manager.allocate_page(PageType::Data)?;
        let mut page = page_manager.read_page(page_id)?;
        
        // 设置测试数据
        for i in 0..100 {
            page.data[i] = (i % 256) as u8;
        }
        
        // 写入并刷新
        page_manager.write_page(Arc::new(page))?;
        page_manager.flush_dirty_pages()?;
        
        // 重新创建页面管理器并读取
        let page_manager2 = PageManager::with_disk_storage(10, &data_file)?;
        let recovered_page = page_manager2.read_page(page_id)?;
        
        // 验证数据完整性
        for i in 0..100 {
            assert_eq!(recovered_page.data[i], (i % 256) as u8);
        }
        
        Ok(())
    }

    /// 测试错误处理
    #[test]
    fn test_error_handling() -> Result<()> {
        let page_manager = PageManager::new(10);
        
        // 测试读取不存在的页面
        let result = page_manager.read_page(999);
        assert!(result.is_ok()); // 应该创建新页面
        
        // 测试无效的页面类型（这个测试可能需要根据实际实现调整）
        let page_id = page_manager.allocate_page(PageType::Data)?;
        assert!(page_id > 0);
        
        Ok(())
    }

    /// 测试并发访问
    #[test]
    fn test_concurrent_access() -> Result<()> {
        use std::thread;
        use std::sync::Arc;
        
        let page_manager = Arc::new(PageManager::new(20));
        let mut handles = vec![];
        
        // 创建多个线程同时分配页面
        for i in 0..5 {
            let pm = Arc::clone(&page_manager);
            let handle = thread::spawn(move || -> Result<()> {
                for j in 0..10 {
                    let page_type = if (i + j) % 2 == 0 { PageType::Data } else { PageType::Index };
                    let page_id = pm.allocate_page(page_type)?;
                    let _page = pm.read_page(page_id)?;
                }
                Ok(())
            });
            handles.push(handle);
        }
        
        // 等待所有线程完成
        for handle in handles {
            handle.join().unwrap()?;
        }
        
        // 验证统计信息
        let stats = page_manager.get_statistics();
        assert_eq!(stats.total_pages, 50); // 5个线程 * 10个页面
        
        Ok(())
    }
}
